home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / misc / amag / sh9301c.lha / Differenzieren(S.91) / How-2-Derive.c < prev    next >
C/C++ Source or Header  |  1992-10-24  |  32KB  |  1,225 lines

  1. #include <ctype.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <math.h>
  6. #include <stdio.h>
  7. #include <intuition/intuition.h>
  8. #include <proto/intuition.h>
  9. #include <proto/exec.h>
  10. #include <proto/graphics.h>
  11.  
  12. struct bits {unsigned K:1,Neg:1,Konst:1;};
  13. typedef union {unsigned mask;struct bits is;} FLAGS;
  14. typedef enum {OP_OPEN=-2,OP_CLOSE,OP_NONE=0,
  15.  OP_ADD,OP_SUB,OP_MUL,OP_DIV,OP_NEG,OP_POT,OP_FUNC1,OP_USERF=100} OP;
  16. typedef enum {PRI_NONE,PRI_ADDSUB,PRI_MULDIV,PRI_NEG,PRI_POT,PRI_FUNC} PRI;
  17. struct Knoten {
  18.  FLAGS flags; OP op; PRI pri;
  19.  short primes;
  20.  struct Knoten *links,*rechts;
  21.  double konst;
  22.  short len; char *term;
  23. } *Root;
  24. BOOL verwende(OP);
  25. struct Knoten *Verschmelze(struct Knoten *,struct Knoten *),
  26.  *Vereinfache(struct Knoten *,struct Knoten *,PRI,struct Knoten *,struct Knoten *,int),
  27.  *Verkette(struct Knoten *,OP,struct Knoten *);
  28. char *Baum_String(struct Knoten *,char *),
  29.  *Baum_zu_String(struct Knoten *,char *);
  30. struct Knoten *Differenziere(struct Knoten *,struct list *),*Regeln(void);
  31.  
  32. char Puffer1[1024],Puffer2[1024],Puffer3[1024],Puffer4[1024];
  33. char *cp,*term,*Beginn;
  34. char *Funktionen[]={"ln","sinh","cosh","sin","cos",
  35. "tanh","coth","tan","cot","log","arcsin","arccos",
  36. "arctan","arccot","sqrt","arsinh","arcosh",
  37. "artanh","arcoth","exp",NULL};
  38. char *FunkMsg[]={"z'/z","z'*cosh z","z'*sinh z","z'*cos z","z'*(-sin z)",
  39. "z'/(cosh z)^2","-z'/(sinh z)^2","z'/(cos z)^2","-z'/(sin z)^2",
  40. "z'/z*log e","z'/sqrt(1-z^2)","-z'/sqrt(1-z^2)",
  41. "z'/(1+z^2)","-z'/(1+z^2)","z'/(2*sqrt(z))","z'/sqrt(1+z^2)",
  42. "z'/sqrt(z^2-1)","z'/(1-z^2)","z'/(1-z^2)","z'*exp(z)"};
  43.  
  44. OP op_stack[1024];
  45. int op_sp,kn_sp;
  46. struct Knoten *kn_stack[1024];
  47. PRI oppri[]={PRI_NONE,PRI_ADDSUB,PRI_ADDSUB,
  48. PRI_MULDIV,PRI_MULDIV,PRI_NEG,PRI_POT};
  49. PRI Pri(OP op) {return op<OP_FUNC1?oppri[op]:PRI_FUNC;}
  50. char chop[]={"+-*/_^"};
  51. #define opnr(c) ((OP)(strchr(chop,c)-chop)+OP_ADD)
  52. #define Op(op) ((op)<OP_FUNC1?&chop[(op)-1]:Funktionen[(op)-OP_FUNC1])
  53. #define kommOp(op) ((op)==OP_MUL || (op)==OP_DIV ? OP_MUL : OP_ADD)
  54. #define nkommOp(op) ((op)==OP_MUL || (op)==OP_DIV ? OP_DIV : OP_SUB)
  55. #define StdKonst(pri) ((pri)==PRI_ADDSUB?0.:1.)
  56. #define inv_konst(d,pri) ((d)?(pri)==PRI_ADDSUB?-(d):1./(d):(errno=EDOM,0.))
  57. #define X(k) ((k)->op==OP_NONE && (k)->len==1 && (k)->term[0]=='x')
  58. #define C(k) ((k)->op==OP_NONE && (k)->flags.is.Konst)
  59.  
  60. void inv_K(struct Knoten *k, PRI pri)
  61. {
  62.   struct Knoten *n=k->links;
  63.   k->links=k->rechts; k->rechts=n;
  64.   k->konst=inv_konst(k->konst,pri);
  65. }
  66.  
  67. void Rechne(struct Knoten *l,OP op,struct Knoten *r)
  68. {
  69.   switch(op) {
  70.     case OP_ADD: l->konst+=r->konst; break;
  71.     case OP_SUB: l->konst-=r->konst; break;
  72.     case OP_MUL: l->konst*=r->konst; break;
  73.     case OP_DIV: if(r->konst) l->konst/=r->konst;
  74.       else errno=EDOM; break;
  75.   }
  76. }
  77.  
  78. void Negiere(struct Knoten *k)
  79. {
  80.   struct Knoten *n;
  81.   if(k->pri==PRI_ADDSUB) {
  82.     k->konst=-k->konst; n=k->links;
  83.     k->links=k->rechts; k->rechts=n;
  84.   }
  85.   else if((k->pri==PRI_MULDIV || k->op==OP_NONE) && k->flags.is.Konst)
  86.     k->konst=-k->konst;
  87.   else k->flags.is.Neg=!k->flags.is.Neg;
  88. }
  89.  
  90. BOOL Term_korrekt(char *term)
  91. {
  92. char c,*lastop=NULL,*p=term;
  93. int kl=0;
  94.   cp=term-1;
  95.   while((c=*++cp)!=0) if(!isspace(c)) {
  96.     if(strchr("()+-*/^",c)) {
  97.       if(c=='(') kl++;
  98.       else if(c==')') {
  99.         if(--kl<0 || lastop+1==cp || cp[-1]=='(') return FALSE;
  100.       } else {
  101.         if(lastop+1==cp || c!='-' && cp[-1]=='(') return FALSE;
  102.         lastop=cp;
  103.       }
  104.     }
  105.     else if(!isalnum(c) && !strchr(".'",c)) return FALSE;
  106.     *p++=c;
  107.   }
  108.   *p=0; return (BOOL)(kl==0);
  109. }
  110.  
  111. struct Knoten *Neuer_Operator(OP op)
  112. {
  113. struct Knoten *k;
  114.   if(!(k=malloc(sizeof(struct Knoten)))) {
  115.     fprintf(stderr,"Speicher voll!\n");
  116.     exit(10);
  117.   }
  118.   k->links=k->rechts=NULL;
  119.   k->flags.mask=0; k->primes=0;
  120.   k->op=op; k->pri=Pri(op);
  121.   if(op<OP_USERF) {
  122.     k->term=Op(op);
  123.     k->len=op>=OP_FUNC1?strlen(k->term):1;
  124.   }
  125.   else {int i;
  126.     k->op=OP_USERF;
  127.     k->term=term+op-OP_USERF;
  128.     if(!strncmp(k->term,"log",3)) k->op=OP_FUNC1+9;
  129.     for(i=0;isalnum(k->term[i]);i++);
  130.     k->len=i;
  131.     while(k->term[i++]=='\'') k->primes++;
  132.   }
  133.   k->konst=0.; return k;
  134. }
  135.  
  136. struct Knoten *NeuerK(OP op)
  137. {
  138.   struct Knoten *k=Neuer_Operator(nkommOp(op));
  139.   k->flags.is.K=k->flags.is.Konst=1;
  140.   k->konst=StdKonst(k->pri);
  141.   return k;
  142. }
  143.  
  144. struct Knoten *Neue_Konst(double d)
  145. {
  146.   struct Knoten *k=Neuer_Operator(OP_NONE);
  147.   k->flags.is.Konst=1;
  148.   k->konst=d; return k;
  149. }
  150.  
  151. struct Knoten *Neues_Blatt(char *cp,char **x)
  152. {
  153. struct Knoten *k=Neuer_Operator(OP_NONE);
  154. char *s;
  155.   if(isdigit(*cp)) {
  156.     sscanf(cp,"%lf",&k->konst);
  157.     if(!(s=strpbrk(cp,"()+-*^/"))) s=strchr(cp,0);
  158.     k->flags.is.Konst=1;
  159.   }
  160.   else {
  161.     k->konst=0.; s=cp;
  162.     while(isalnum(*++s));
  163.   }
  164.   k->term=cp; k->len=s-cp;
  165.   *x=s; return k;
  166. }
  167.  
  168. struct Knoten *Baum_aufbauen(char *cp)
  169. {
  170. int i,l; char c;
  171. PRI p,p2; OP op,op2;
  172.   term=cp;
  173.   while((c=*cp)!=0) {
  174.     if(c=='(') op_stack[op_sp++]=OP_OPEN;
  175.     else if(isalnum(c)) {
  176.       if(isalpha(c)) {
  177.         for(i=0;Funktionen[i];i++)
  178.           if(!strncmp(Funktionen[i],cp,l=strlen(Funktionen[i]))) {
  179.             op=OP_FUNC1+i;
  180.             if(op==OP_FUNC1+9) {
  181.               op=(cp-term)+OP_USERF;
  182.               while(isalnum(cp[3])) cp++;
  183.             }
  184. function:   p=PRI_FUNC; cp+=l-1;
  185.             goto operator;
  186.           }
  187.         for(l=0;isalnum(cp[l])||cp[l]=='\'';l++);
  188.         if(cp[l]=='(') {
  189.           op=(cp-term)+OP_USERF;
  190.       goto function;
  191.         }
  192.       }
  193.       kn_stack[kn_sp++]=Neues_Blatt(cp,&cp);
  194.       cp--;
  195.     }
  196.     else if(c==')')
  197.       for(;;) {
  198.         if(!op_sp) goto error;
  199.         op=op_stack[--op_sp];
  200.         if(op!=OP_OPEN) {if(!verwende(op)) goto error;}
  201.         else break;
  202.       }
  203.     else if(strchr(chop,c)) {
  204.       op=opnr(c); p=Pri(op);
  205.       if(op==OP_SUB && (cp==term || cp[-1]=='(')) {
  206.         op=OP_NEG;
  207.         p=PRI_NEG;
  208.       }
  209. operator:
  210.       while(op_sp) {
  211.         op2=op_stack[op_sp-1];
  212.         p2=Pri(op2);
  213.         if(op2==OP_OPEN || p2<p || (p==PRI_FUNC || p==PRI_POT) && p2==p) break;
  214.         --op_sp;
  215.         if(!verwende(op2)) goto error;
  216.       }
  217.       op_stack[op_sp++]=op;
  218.     }
  219.     else goto error;
  220.     cp++;
  221.   }
  222.   while(op_sp) {
  223.     op2=op_stack[--op_sp];
  224.     if(op2==OP_CLOSE) goto error;
  225.     if(!verwende(op2)) goto error;
  226.   }
  227.   if(kn_sp!=1) goto error;
  228.   return kn_stack[--kn_sp];
  229. error:
  230.   while(kn_sp) free(kn_stack[--kn_sp]);
  231.   return NULL;
  232. }
  233.  
  234. void Baum_abbauen(struct Knoten *k)
  235. {
  236.   if(k) {
  237.     if(k->links) Baum_abbauen(k->links);
  238.     if(k->rechts) Baum_abbauen(k->rechts);
  239.     free(k);
  240.   }
  241. }
  242.  
  243. struct Knoten *Sinnlos(struct Knoten *k)
  244. {
  245.   if(!k->links && !k->rechts) {
  246.     k->flags.is.K=0;
  247.     k->op=OP_NONE; k->pri=PRI_NONE;
  248.   }
  249.   if(k->pri==PRI_MULDIV && k->flags.is.Konst && k->konst==0.) {
  250.     Baum_abbauen(k);
  251.     return Neue_Konst(0.);
  252.   }
  253.   if(k->op==OP_POT && k->rechts->flags.is.Konst && k->rechts->op==OP_NONE) {
  254.     if(k->rechts->konst==0.) {
  255.       Baum_abbauen(k);
  256.       return Neue_Konst(1.);
  257.     }
  258.     if(k->rechts->konst==1.) {
  259.       struct Knoten *n=k->links;
  260.       k->links=NULL;
  261.       Baum_abbauen(k);
  262.       return Sinnlos(n);
  263.     }
  264.   }
  265.   if(k->flags.is.Konst && k->links && !k->rechts && !k->links->links)
  266.     if(k->konst==StdKonst(k->pri) || k->pri==PRI_MULDIV && k->konst==-1.) {
  267.       struct Knoten *n=k->links->rechts;
  268.       k->links->rechts=NULL;
  269.       if(k->konst==-1.) Negiere(n);
  270.       Baum_abbauen(k);
  271.       return Sinnlos(n);
  272.     }
  273.   return k;
  274. }
  275.  
  276. struct Knoten *verkette_Pot(struct Knoten *l,struct Knoten *r)
  277. {
  278. struct Knoten *k;
  279.   if(r->op==OP_NONE && r->flags.is.Konst &&
  280.      l->op==OP_NONE && l->flags.is.Konst) {
  281.     l->konst=pow(l->konst,r->konst);
  282.     Baum_abbauen(r); return l;
  283.   }
  284.   k=Neuer_Operator(OP_POT);
  285.   k->links=l; k->rechts=r;
  286.   return Sinnlos(k);
  287. }
  288.  
  289. BOOL verwende(OP op)
  290. {
  291. struct Knoten *l,*r,*k;
  292.   #define kn_pop(w) {if(kn_sp<=0) return FALSE;(w)=kn_stack[--kn_sp];}
  293.   kn_pop(r);
  294.   switch(Pri(op)) {
  295.     case PRI_POT:
  296.       kn_pop(l);
  297.       k=verkette_Pot(l,r); break;
  298.     case PRI_ADDSUB:
  299.     case PRI_MULDIV:
  300.       kn_pop(l);
  301.       k=Verkette(l,op,r); break;
  302.     case PRI_NEG: Negiere(k=r);break;
  303.     case PRI_FUNC:
  304.       k=Neuer_Operator(op);
  305.       k->rechts=r; break;
  306.   }
  307.   kn_stack[kn_sp++]=k; return TRUE;
  308. }
  309.  
  310. struct Knoten *Verkette(struct Knoten *l,OP op,struct Knoten *r)
  311. {
  312. OP kop=kommOp(op),nkop=nkommOp(op);
  313. PRI pri=Pri(op);
  314. struct Knoten *k,*o;
  315. BOOL l_homogen=l->flags.is.Konst && l->op==OP_NONE || l->pri==pri;
  316. BOOL r_homogen=r->flags.is.Konst && r->op==OP_NONE || r->pri==pri;
  317.   if(op==OP_POT) return verkette_Pot(l,r);
  318.   if(!r_homogen) {
  319.     o=Neuer_Operator(op);
  320.     if(l_homogen) {
  321.       if(l->op==OP_NONE) {
  322.         k=NeuerK(op);
  323.         k->konst=l->konst;
  324.         Baum_abbauen(l);
  325.       }
  326.       else k=l;
  327.       o->rechts=r;
  328.       k=Verschmelze(k,o);
  329.     }
  330.     else {
  331.       struct Knoten *n=Neuer_Operator(kop);
  332.       n->rechts=l; o->rechts=r;
  333.       k=Verschmelze(NeuerK(op),n);
  334.       k=Verschmelze(k,o);
  335.     }
  336.   }
  337.   else {
  338.     if(!l_homogen) {
  339.       o=Neuer_Operator(op);
  340.       if(r->op==OP_NONE) {
  341.         k=NeuerK(op);
  342.         k->konst=op==kop?r->konst:inv_konst(r->konst,pri);
  343.         o->rechts=l; o->op=kop;
  344.         k=Verschmelze(k,o);
  345.         Baum_abbauen(r);
  346.       }
  347.       else {
  348.         k=r;
  349.         if(op==nkop) {
  350.           inv_K(k,pri);
  351.           o->op=kop;
  352.         }
  353.         o->rechts=l;
  354.         k=Verschmelze(k,o);
  355.       }
  356.     }
  357.     else {
  358.       if(l->op==OP_NONE) {
  359.         if(r->op==OP_NONE) {
  360.           Rechne(k=l,op,r);
  361.           Baum_abbauen(r);
  362.         }
  363.         else {
  364.           k=r;
  365.           if(op==nkop) inv_K(k,pri);
  366.           Rechne(k,kop,l);
  367.           Baum_abbauen(l);
  368.         }
  369.       }
  370.       else {
  371.         if(r->op==OP_NONE) {
  372.           Rechne(k=l,op,r);
  373.           Baum_abbauen(r);
  374.         }
  375.         else {
  376.           Rechne(l,op,r);
  377.           o=r->links;
  378.           while(o) {
  379.             k=o->links;
  380.             o->links=NULL;
  381.             if(op==nkop) o->op=nkop;
  382.             l=Verschmelze(l,o);
  383.             o=k;
  384.           }
  385.           o=r->rechts;
  386.           while(o) {
  387.             k=o->links;
  388.             o->links=NULL;
  389.             if(op==kop) o->op=nkop;
  390.             l=Verschmelze(l,o);
  391.             o=k;
  392.           }
  393.           r->links=r->rechts=NULL;
  394.           Baum_abbauen(r); k=l;
  395.         }
  396.       }
  397.     }
  398.   }
  399.   return Sinnlos(k);
  400. }
  401.  
  402. struct Knoten *BaumKopie(struct Knoten *k)
  403. {
  404. struct Knoten *n=NULL;
  405.   if(k) {
  406.     n=Neuer_Operator(OP_NONE);
  407.     *n=*k;
  408.     n->links=BaumKopie(k->links);
  409.     n->rechts=BaumKopie(k->rechts);
  410.   }
  411.   return n;
  412. }
  413.  
  414. TreeCmp(const void *l,const void *r)
  415. {
  416.   Baum_zu_String((*(struct Knoten *const*)l)->rechts,Puffer3);
  417.   Baum_zu_String((*(struct Knoten *const*)r)->rechts,Puffer4);
  418.   return strcmp(Puffer3,Puffer4);
  419. }
  420.  
  421. struct Knoten *sortK(struct Knoten *k)
  422. {
  423. void SortBaum(struct Knoten *);
  424. struct Knoten *n,**nl;
  425. int i,j;
  426.   for(i=0,n=k;n;i++,n=n->links) SortBaum(n->rechts);
  427.   if(i>1) {
  428.     if(!(nl=(struct Knoten **)malloc(sizeof(n)*i))) {
  429.       fprintf(stderr,"Speicher voll!\n");
  430.       exit(10);
  431.     }
  432.     for(n=k,j=0;n;n=n->links,j++) nl[j]=n;
  433.     qsort((void*)nl,i,sizeof(n),TreeCmp);
  434.     for(k=n=*nl,j=1;j<i;n=n->links,j++) n->links=nl[j];
  435.     n->links=NULL; free(nl);
  436.   }
  437.   return k;
  438. }
  439.  
  440. void SortBaum(struct Knoten *k)
  441. {
  442.   if(!k) return;
  443.   if(k->flags.is.K) {
  444.     k->links=sortK(k->links);
  445.     k->rechts=sortK(k->rechts);
  446.   } else {
  447.     SortBaum(k->links); SortBaum(k->rechts);
  448.   }
  449. }
  450.  
  451. void Wegen_NegPot(struct Knoten *o,struct Knoten *k)
  452. {
  453.   struct Knoten *n=o->rechts;
  454.   if(n->op==OP_POT) {
  455.     do n=n->rechts;
  456.     while(n->op==OP_POT);
  457.     if(n->op==OP_NONE && n->flags.is.Konst && n->konst<0.) {
  458.       o->op=o->op==OP_MUL?OP_DIV:OP_MUL;
  459.       n->konst=-n->konst;
  460.       if(n->konst==1.)
  461.     for(n=o;n->rechts && n->rechts->op==OP_POT;n=n->rechts)
  462.       n->rechts=Sinnlos(n->rechts);
  463.     }
  464.   }
  465.   else if(n->flags.is.Neg) {
  466.     n->flags.is.Neg=!n->flags.is.Neg;
  467.     Negiere(k);
  468.   }
  469. }
  470.  
  471. void Wegen_NegVorz(struct Knoten *o)
  472. {
  473.   if(o->rechts->flags.is.Neg) {
  474.     o->rechts->flags.is.Neg=0;
  475.     o->op=o->op==OP_ADD?OP_SUB:OP_ADD;
  476.   }
  477.   else if(o->rechts->flags.is.Konst && (o->rechts->op==OP_NONE ||
  478.         o->rechts->pri==PRI_MULDIV) && o->rechts->konst<0.) {
  479.     o->rechts->konst=-o->rechts->konst;
  480.     o->op=o->op==OP_ADD?OP_SUB:OP_ADD;
  481.   }
  482. }
  483.  
  484. struct Knoten *Ignoriere(struct Knoten *k,PRI pri)
  485. {
  486.   if(pri==PRI_ADDSUB && k->pri==PRI_MULDIV && !k->rechts && k->links &&
  487.     !k->links->links && k->links->rechts)
  488.       return k->links->rechts;
  489.   else if(pri==PRI_MULDIV && k->op==OP_POT && k->rechts->op==OP_NONE &&
  490.     k->rechts->flags.is.Konst)
  491.       return k->links;
  492.   return k;
  493. }
  494.  
  495. char *SortB_String(struct Knoten *k,char *s)
  496. {
  497.   struct Knoten *cpy=BaumKopie(k);
  498.   SortBaum(cpy); s=Baum_zu_String(cpy,s);
  499.   Baum_abbauen(cpy); return s;
  500. }
  501.  
  502. struct Knoten *Verschmelze(struct Knoten *k,struct Knoten *o)
  503. {
  504. OP kop;
  505. struct Knoten *l,*r,*p1,*p2;
  506. int v1=1,v2=1;
  507. PRI pri=k->pri;
  508.   if(!o) return k;
  509.   kop=kommOp(o->op);
  510.   if(o->pri==PRI_MULDIV) Wegen_NegPot(o,k);
  511.   else Wegen_NegVorz(o);
  512.   SortB_String(Ignoriere(o->rechts,pri),Puffer1);
  513.   l=k->links; p1=NULL;
  514.   while(l) {
  515.     SortB_String(Ignoriere(l->rechts,pri),Puffer2);
  516.     v1=strcmp(Puffer2,Puffer1);
  517.     if(v1==0 || !l->links) break;
  518.     p1=l; l=l->links;
  519.   }
  520.   r=k->rechts; p2=NULL;
  521.   while(r) {
  522.     SortB_String(Ignoriere(r->rechts,pri),Puffer2);
  523.     v2=strcmp(Puffer2,Puffer1);
  524.     if(v2==0 || !r->links) break;
  525.     p2=r; r=r->links;
  526.   }
  527.   if(v1==0) k=Vereinfache(l,o,pri,k,p1,1);
  528.   else if(v2==0) k=Vereinfache(r,o,pri,k,p2,2);
  529.   else if(o->op==kop) {
  530.     if(!l) l=k;
  531.     o->links=l->links; l->links=o;
  532.   } else {
  533.     o->op=kop;
  534.     if(r) {
  535.       o->links=r->links; r->links=o;
  536.     } else {
  537.       o->links=k->rechts; k->rechts=o;
  538.     }
  539.   }
  540.   return k;
  541. }
  542.  
  543. struct Knoten *Vereinfache(struct Knoten *o1,struct Knoten *o2,PRI pri,
  544.   struct Knoten *k,struct Knoten *p,int von)
  545. {
  546. struct Knoten *n,tmp;
  547. OP op;
  548.   tmp.konst=1.;
  549.   if(pri==PRI_ADDSUB) {
  550.     n=o1->rechts;
  551.     if(n->pri!=PRI_MULDIV) {
  552.       n=NeuerK(OP_MUL);
  553.       n->links=Neuer_Operator(OP_MUL);
  554.       n->links->rechts=o1->rechts;
  555.       o1->rechts=n;
  556.     }
  557.     op=o2->op;
  558.     if(von==2) op=op==OP_ADD?OP_SUB:OP_ADD;
  559.     if(o2->rechts->pri==PRI_MULDIV)
  560.       Rechne(n,op,o2->rechts);
  561.     else Rechne(n,op,&tmp);
  562.     Baum_abbauen(o2);
  563.     if(p) p->links=o1->links;
  564.     else if(von==1) k->links=o1->links;
  565.     else k->rechts=o1->links;
  566.     o1->links=NULL;
  567.     if(von==2) o1->op=OP_SUB;
  568.   }
  569.   else if(pri==PRI_MULDIV) {
  570.     if(o1->rechts->op!=OP_POT || o1->rechts->rechts->flags.is.Konst==0
  571.       || o1->rechts->rechts->op!=OP_NONE) {
  572.       n=Neuer_Operator(OP_POT);
  573.       n->rechts=Neue_Konst(1.);
  574.       n->links=o1->rechts;
  575.       o1->rechts=n;
  576.     }
  577.     else n=o1->rechts;
  578.     op=o2->op==OP_MUL?OP_ADD:OP_SUB;
  579.     if(von==2) op=op==OP_ADD?OP_SUB:OP_ADD;
  580.     if(o2->rechts->op==OP_POT && o2->rechts->rechts->flags.is.Konst &&
  581.       o2->rechts->rechts->op==OP_NONE)
  582.       Rechne(n->rechts,op,o2->rechts->rechts);
  583.     else Rechne(n->rechts,op,&tmp);
  584.     Baum_abbauen(o2);
  585.     if(p) p->links=o1->links;
  586.     else if(von==1) k->links=o1->links;
  587.     else k->rechts=o1->links;
  588.     o1->links=NULL;
  589.     if(von==2) o1->op=OP_DIV;
  590.   }
  591.   o1->rechts=Sinnlos(o1->rechts);
  592.   if(o1->rechts->op==OP_NONE && o1->rechts->flags.is.Konst)
  593.     if(pri==PRI_ADDSUB && o1->rechts->konst==0 ||
  594.       pri==PRI_MULDIV && o1->rechts->konst==1.) {
  595.       Baum_abbauen(o1);
  596.       o1=NULL;
  597.     }
  598.   k=Verschmelze(k,o1);
  599.   return Sinnlos(k);
  600. }
  601.  
  602. BOOL dop_klammer(char **sp)
  603. {
  604.   return (*sp!=Beginn && (*sp)[-1]!='(')?((*sp)++[0]='(',TRUE):FALSE;
  605. }
  606.  
  607. BOOL pri_klammer(struct Knoten *v,struct Knoten *s,char **sp)
  608. {
  609.   return (v->pri>s->pri && s->pri!=PRI_NONE || (v->pri==s->pri || s->pri==PRI_FUNC) && v->pri==PRI_POT || v->op==OP_USERF)?\
  610.     ((*sp)++[0]='(',TRUE):FALSE;
  611. }
  612.  
  613. void klammer_zu(char **sp,BOOL kl)
  614. {
  615.   if(kl) (*sp)++[0]=')';
  616. }
  617.  
  618. char *cut(char *s)
  619. {
  620. char *cp=s;
  621.   do;while(*--cp=='0');
  622.   if(isdigit(*cp)) s=cp+1;
  623.   else if(*cp=='.') s=cp;
  624.   *s=0; return s;
  625. }
  626.  
  627. char *Baum_zu_String(struct Knoten *k,char *s)
  628. {
  629.   if(k) s=Baum_String(k,Beginn=s);
  630.   else *s++='0';
  631.   *s=0; return s;
  632. }
  633.  
  634. char *Baum_String(struct Knoten *k,char *s)
  635. {
  636. int i;
  637.   if(k->op==OP_NONE) {
  638.     if(k->flags.is.Konst) {
  639.       sprintf(s,"%lf",k->konst);
  640.       s=cut(strchr(s,0));
  641.     }
  642.     else if(k->flags.is.Neg) {
  643.       BOOL kl=dop_klammer(&s);
  644.       *s++='-';
  645.       strncpy(s,k->term,k->len); s+=k->len;
  646.       klammer_zu(&s,kl);
  647.     }
  648.     else {
  649.       strncpy(s,k->term,k->len); s+=k->len;
  650.     }
  651.     return s;
  652.   }
  653.   if(k->op>=OP_FUNC1) {
  654.     BOOL kl1,kl2;
  655.     if(k->flags.is.Neg) {
  656.       kl1=dop_klammer(&s);
  657.       *s++='-';
  658.     }
  659.     strncpy(s,k->term,k->len);
  660.     s+=k->len;
  661.     for(i=0;i<k->primes;i++) *s++='\'';
  662.     kl2=pri_klammer(k,k->rechts,&s);
  663.     if(!kl2) *s++=' ';
  664.     s=Baum_String(k->rechts,s);
  665.     klammer_zu(&s,kl2);
  666.     if(k->flags.is.Neg) klammer_zu(&s,kl1);
  667.     return s;
  668.   }
  669.   if(k->op==OP_POT) {
  670.     BOOL kl1,kl2;
  671.     if(k->flags.is.Neg) {
  672.       kl1=dop_klammer(&s);
  673.       *s++='-';
  674.     }
  675.     kl2=pri_klammer(k,k->links,&s);
  676.     s=Baum_String(k->links,s);
  677.     klammer_zu(&s,kl2);
  678.     *s++='^';
  679.     kl2=pri_klammer(k,k->rechts,&s);
  680.     s=Baum_String(k->rechts,s);
  681.     klammer_zu(&s,kl2);
  682.     if(k->flags.is.Neg) klammer_zu(&s,kl1);
  683.     return s;
  684.   }
  685.   if(k->flags.is.K) {
  686.     BOOL noop=FALSE,kl1,kl2;
  687.     struct Knoten *n;
  688.     if(k->flags.is.Konst && k->konst!=StdKonst(k->pri)) {
  689.       if(k->konst<0.) kl1=dop_klammer(&s);
  690.       sprintf(s,"%lf",k->konst);
  691.       s=cut(strchr(s,0));
  692.       if(k->konst<0.) klammer_zu(&s,kl1);
  693.     }
  694.     else if(k->links==NULL) {
  695.       if(k->pri==PRI_MULDIV) *s++='1';
  696.     }
  697.     else noop=TRUE;
  698.     n=k->links;
  699.     while(n) {
  700.       if(!noop) *s++=*Op(n->op);
  701.       else noop=FALSE;
  702.       kl2=pri_klammer(n,n->rechts,&s);
  703.       s=Baum_String(n->rechts,s);
  704.       klammer_zu(&s,kl2);
  705.       n=n->links;
  706.     }
  707.     n=k->rechts;
  708.     if(n) {
  709.       *s++=*Op(k->op);
  710.       noop=TRUE;
  711.       if(n->links) *s++='(';
  712.       while(n) {
  713.         if(!noop) *s++=*Op(n->op);
  714.         else noop=FALSE;
  715.         kl2=pri_klammer(n,n->rechts,&s);
  716.         s=Baum_String(n->rechts,s);
  717.         klammer_zu(&s,kl2);
  718.         n=n->links;
  719.       }
  720.       if(k->rechts->links) *s++=')';
  721.     }
  722.   }
  723.   return s;
  724. }
  725.  
  726. #define WIDTH 60
  727. struct node {
  728.   struct node *prev,*next;
  729.   char s[WIDTH+1];
  730. };
  731. struct list {
  732.   struct node *first,*last;
  733. };
  734.  
  735. struct Knoten *u,*v,*a,*b,*K,*D;
  736. char s1[20],s2[20],*muster,
  737. *dMul[3]={"*ub","*va","+*av*bu"},
  738. *dDiv[3]={"/_*ub^v2","/av","/-*av*bu^v2"},
  739. *dPot[3]={"*^uv*#01ub","*v*^u-v1a","*^uv+*b#01u*/vua"},
  740. *dFunk[]={"/bv","*#03vb","*#02vb","*#05vb","*_#04vb",
  741. "/b^#03v2","_/b^#02v2","/b^#05v2","_/b^#04v2","*/bv#10e",
  742. "/b#15-1^v2","_/b#15-1^v2","/b+1^v2","_/b+1^v2","/b*2#15v",
  743. "/b#15+1^v2","/b#15-^v21","/b-1^v2","/b-1^v2","*b#20v"};
  744. char *PotMsg1[3]={
  745. "Bei &k ist die Basis &u konstant. Man verfährt wie folgt: "
  746. "(c^v)'=ln c*c^v*v', mit c=&u und v=&v.",
  747. "&k ist ein Term mit konstanter Potenz &v. Die Basis b ist &u. "
  748. "Solche Terme differenziert man so: (b^c)'=c*b^(c-1)*b'.",
  749. "Bei &k sind weder die Basis u=&u noch v=&v konstant. Man differenziert "
  750. "Ausdrücke dieser Art folgendermaßen: (u^v)'=u^v*(v'*ln u+v*u'/u)."},
  751. *PotMsg2[2]={"Differenzieren wir also einmal v.",
  752. "Berechnen wir also die Ableitung der Basis b."},
  753. *PotMsg3[3]={"Mit c=&u, v=&v und v'=&b wird &k nach (c^v)'=ln c*c^v*v' zu &d.",
  754. "Damit wird &k nach (b^c)'=c*b^(c-1)*b' zu &d.",
  755. "Mit u=&u, v=&v, u'=&a und v'=&b ergibt sich nach "
  756. "(u^v)'=u^v*(v'*ln u+v*u'/u) aus &k das Ergebnis &d."},
  757. *PotMsg4[2]={"v' ist dabei 1, &k wird also zu &d.",
  758. "b' ist natürlich 1 und so erhalten wir &d."},
  759. *ASMsg[3]={"Terme, die durch + oder - getrennt sind, werden einzeln "
  760. "differenziert und anschließend wieder zusammengesetzt.",
  761. "Die Konstante &# wird beim Differenzieren zu 0, wir müssen also"
  762. " nur den Rest ableiten.","Da wir ja &k zu differenzieren"
  763. " hatten, dürfen wir natürlich nicht auf das Minus vergessen"
  764. " und erhalten deshalb &d."},
  765. *MDMsg[5]={"Bei einer Division kommt die Quotientenregel "
  766. "(u/v)'=(u'*v-v'*u)/v^2 zum Einsatz. Hier ist u=&# eine Konstante"
  767. ", die Ableitung u' also 0. Wir differenzieren also nach -v'*u"
  768. "/v^2, mit v=&v.","Damit erhalten wir für &k nach -v'*c/v^2 mit v=&v"
  769. " und v'=&b schlußendlich &d.","Der konstante Faktor &# bleibt"
  770. " beim Differenzieren unverändert, wir differenzieren also erst"
  771. " einmal den Rest.","Wir haben bei &k eine Division von u=&u durch"
  772. " v=&v. Hier gilt die Quotientenregel (u/v)'=(u'*v-v'*u)/v^2.",
  773. "Mit u=&u, v=&v, u'=&a und v'=&b wird &k nach der Quotientenregel"
  774. " (u/v)'=(u'*v-v'*u)/v^2 zu &d."},
  775. *MMsg[2]={"Bei einem Produkt zweier Terme u=&u und v=&v kommt"
  776. " die Produktregel (u*v)'=u'*v+v'*u zum Einsatz.",
  777. "Mit u=&u, v=&v, u'=&a und v'=&b ergibt sich nach (u*v)'="
  778. "u'*v+v'*u aus &k eben &d."};
  779.  
  780. struct node *new_node(struct list *l)
  781. {
  782.   struct node *n=malloc(sizeof(struct node));
  783.   if(n==NULL) {
  784.     fprintf(stderr,"Speicher voll!\n");
  785.     exit(10);
  786.   }
  787.   n->prev=n->next=NULL;
  788.   if(l->first) {
  789.     l->last->next=n;
  790.     n->prev=l->last;
  791.     l->last=n;
  792.   }
  793.   else l->first=l->last=n;
  794.   return n;
  795. }
  796.  
  797. void behandle(char *src,char *dest)
  798. {
  799. char c;
  800.   while((c=*src++)!=0)
  801.     if(c!='&') *dest++=c;
  802.     else switch(*src++) {
  803.       case 'a': dest=Baum_zu_String(a,dest);break;
  804.       case 'b': dest=Baum_zu_String(b,dest);break;
  805.       case 'u': dest=Baum_zu_String(u,dest);break;
  806.       case 'v': dest=Baum_zu_String(v,dest);break;
  807.       case 'k': dest=Baum_zu_String(K,dest);break;
  808.       case 'd': dest=Baum_zu_String(D,dest);break;
  809.       case '1': strcpy(dest,s1);dest+=strlen(s1);break;
  810.       case '2': strcpy(dest,s2);dest+=strlen(s2);break;
  811.       case '#': sprintf(dest,"%lf",K->konst);
  812.         dest=cut(strchr(dest,0));break;
  813.     }
  814.   *dest=0;
  815. }
  816.  
  817. void Schreibe(struct list *l,char *s)
  818. {
  819. static char um[]={" =+-*^/"};
  820. struct node *n=new_node(l);
  821.   if(strlen(s)<=WIDTH) strcpy(n->s,s);
  822.   else {
  823.     int i=WIDTH+1;
  824.     while(--i>0) if(strchr(um,s[i])) break;
  825.     if(i<0) i=WIDTH;
  826.     else i++;
  827.     strncpy(n->s,s,i);
  828.     n->s[s[i-1]!=' '?i--:i-1]=0;
  829.     Schreibe(l,s+i);
  830.   }
  831. }
  832.  
  833. void Ausgabe(struct list *l,char *s)
  834. {
  835.   behandle(s,Puffer1); Schreibe(l,Puffer1);
  836. }
  837.  
  838. void anhaengen(struct list *l,struct list *r)
  839. {
  840.   if(!l->first) *l=*r;
  841.   else if(r->first) {
  842.     l->last->next=r->first;
  843.     r->first->prev=l->last;
  844.     l->last=r->last;
  845.   }
  846. }
  847.  
  848. void Loesche(struct list *l)
  849. {
  850. struct node *n=l->first,*m;
  851.   while(n) {
  852.     m=n; n=n->next; free(m);
  853.   }
  854. }
  855.  
  856. void beide_abl(struct list *l,struct list *r,struct list *li)
  857. {
  858.   if(X(u)) {
  859.     Ausgabe(li,"Da u=x, ist u'=1. Berechnen wir also die Ableitung von v=&v.");
  860.     Loesche(l);
  861.     anhaengen(li,r);
  862.   }
  863.   else if(X(v)) {
  864.     Ausgabe(li,"Da v=x, ist v'=1. Berechnen wir also die Ableitung von u=&u.");
  865.     Loesche(r);
  866.     anhaengen(li,l);
  867.   }
  868.   else {
  869.     Ausgabe(li,"Berechnen wir zuerst einmal u'.");
  870.     anhaengen(li,l);
  871.      Ausgabe(li,"Für &k brauchen wir noch die Ableitung von v=&v.");
  872.     anhaengen(li,r);
  873.   }
  874. }
  875.  
  876. Art(void)
  877. {
  878.   int art=2;
  879.   if(!a || a->op==OP_NONE && a->flags.is.Konst && a->konst==0.) {
  880.     Baum_abbauen(a); a=NULL;
  881.     art-=2;
  882.   }
  883.   if(!b || b->op==OP_NONE && b->flags.is.Konst && b->konst==0.) {
  884.     Baum_abbauen(b); b=NULL;
  885.     art--;
  886.   }
  887.   return art;
  888. }
  889.  
  890. struct Knoten *diffAdd(struct Knoten *k,struct list *li)
  891. {
  892. struct Knoten *l,*r;
  893.   if(k) {
  894.     r=Differenziere(k->rechts,li);
  895.     l=diffAdd(k->links,li);
  896.     if(l) r=Verkette(l,OP_ADD,r);
  897.     return r;
  898.   }
  899.   return NULL;
  900. }
  901.  
  902. struct Knoten *diffMul(struct Knoten *k,struct list *li)
  903. {
  904. struct Knoten *l,*r;
  905. int art;
  906. struct list ll,rl;
  907.   if(k) {
  908.     ll.first=rl.first=NULL;
  909.     r=Differenziere(k->rechts,&ll);
  910.     l=diffMul(k->links,&rl);
  911.     if(!l) {
  912.       anhaengen(li,&ll);Loesche(&rl);
  913.       return r;
  914.     }
  915.     v=NeuerK(OP_MUL);
  916.     v->links=BaumKopie(k->links);
  917.     v=Sinnlos(v);
  918.     u=k->rechts;
  919.     b=l; a=r; art=Art();
  920.     if(art<0) return Neue_Konst(0.);
  921.     muster=dMul[art];
  922.     D=l=Sinnlos(Regeln());
  923.     K=NeuerK(OP_MUL);
  924.     K->links=k;
  925.     Ausgabe(li,MMsg[0]);
  926.     beide_abl(&ll,&rl,li);
  927.     Ausgabe(li,MMsg[1]);
  928.     K->links=NULL;
  929.     Baum_abbauen(K); Baum_abbauen(v);
  930.     Baum_abbauen(a); Baum_abbauen(b);
  931.     return l;
  932.   }
  933.   return NULL;
  934. }
  935.  
  936. struct Knoten *Regeln(void)
  937. {
  938. struct Knoten *k;
  939. int d;
  940.   switch(d=*muster++) {
  941.     case 'a': k=BaumKopie(a);break;
  942.     case 'b': k=BaumKopie(b);break;
  943.     case 'u': k=BaumKopie(u);break;
  944.     case 'v': k=BaumKopie(v);break;
  945.     case '_': Negiere(k=Regeln());break;
  946.     case 'e': k=Neues_Blatt("e",&cp);break;
  947.     case '#':
  948.       sscanf(muster,"%d",&d);
  949.       muster+=2;
  950.       k=Neuer_Operator(d+OP_FUNC1-1);
  951.       if(d==10) {k->term=K->term;k->len=K->len;}
  952.       k->rechts=Regeln();
  953.       break;
  954.     default:
  955.       if(isdigit(d)) k=Neue_Konst((double)(d-'0'));
  956.       else {
  957.         k=Regeln();
  958.         k=Verkette(k,opnr(d),Regeln());
  959.       }
  960.   }
  961.   return k;
  962. }
  963.  
  964. struct Knoten *Differenziere(struct Knoten *k,struct list *li)
  965. {
  966. struct Knoten *d;
  967. int art;
  968. struct list ll,rl;
  969.   ll.first=rl.first=NULL; K=k;
  970.   if(k->op==OP_NONE) {
  971.     if(k->flags.is.Konst==0 && k->len==1 && *k->term=='x') {
  972.       Ausgabe(li,"x abgeleitet ergibt 1.");
  973.       return Neue_Konst(k->flags.is.Neg?-1.:1.);
  974.     }
  975.     Ausgabe(li,"Die Konstante &k abgeleitet ergibt 0.");
  976.     return Neue_Konst(0.);
  977.   }
  978.   if(k->op>=OP_FUNC1) {
  979.     if(C(k->rechts)) {
  980.       Ausgabe(li,"&k ist konstant, die Ableitung davon also 0.");
  981.       Loesche(&rl);
  982.       return Neue_Konst(0.);
  983.     }
  984.     b=Differenziere(k->rechts,&rl);
  985.     v=k->rechts;
  986.     if(k->op>=OP_USERF) {
  987.       u=BaumKopie(k);
  988.       u->primes++; muster="*ub";
  989.     }
  990.     else muster=dFunk[k->op-OP_FUNC1];
  991.     K=k; d=Regeln();
  992.     if(k->op>=OP_USERF) Baum_abbauen(u);
  993.     if(k->flags.is.Neg) Negiere(d);
  994.     d=D=Sinnlos(d); K=k;
  995.     strncpy(s1,k->term,k->len);
  996.     strcpy(s1+k->len," z");
  997.     if(!X(v)) {
  998.       if(k->op>=OP_USERF) Ausgabe(li,"Leiten wir die Funktion &k ab und multiplizieren wir sie mit der inneren Ableitung z'. Das Argument z ist &v.");
  999.       else {
  1000.         strcpy(s2,FunkMsg[k->op-OP_FUNC1]);
  1001.         Ausgabe(li,"Allgemein wird eine Funktion &1 beim Differenzieren zu &2. Hier ist z=&v.");
  1002.       }
  1003.       Ausgabe(li,"Berechnen wir die Ableitung davon.");
  1004.       anhaengen(li,&rl);
  1005.       if(k->op>=OP_USERF) Ausgabe(li,"Die Ableitung von &k ist also &d.");
  1006.       else Ausgabe(li,"Wir bekommen also aus &1=&k nach der Vorschrift (&1)'=&2 als Ergebnis &d.");
  1007.     }
  1008.     else {
  1009.       Ausgabe(li,"Die Funktion &k abgeleitet wird zu &d.");
  1010.       Loesche(&rl);
  1011.     }
  1012.     Baum_abbauen(b);
  1013.     return d;
  1014.   }
  1015.   if(k->op==OP_POT) {
  1016.     d=Differenziere(k->links,&ll);
  1017.     b=Differenziere(k->rechts,&rl);
  1018.     a=d;
  1019.     u=BaumKopie(k->links);
  1020.     v=BaumKopie(k->rechts);
  1021.     if((art=Art())<0) {
  1022.       Ausgabe(li,"&k ist konstant, die Ableitung also 0.");
  1023.       Loesche(&ll);Loesche(&rl);
  1024.       return Neue_Konst(0.);
  1025.     }
  1026.     muster=dPot[art];
  1027.     d=Regeln();
  1028.     if(k->flags.is.Neg) Negiere(d);
  1029.     D=d=Sinnlos(d); K=k;
  1030.     Ausgabe(li,PotMsg1[art]);
  1031.     if(art<2) {
  1032.       if(!X(u) && !X(v)) {
  1033.         Ausgabe(li,PotMsg2[art]);
  1034.         anhaengen(li,art?&ll:&rl);
  1035.         Ausgabe(li,PotMsg3[art]);
  1036.         Loesche(art?&rl:&ll);
  1037.       }
  1038.       else {
  1039.         Loesche(&ll);Loesche(&rl);
  1040.         Ausgabe(li,PotMsg4[art]);
  1041.       }
  1042.     }
  1043.     else {
  1044.       if(X(u) && X(v)) {
  1045.         Ausgabe(li,"Da u und v=x, sind sowohl u' als auch v'=1.");
  1046.         Loesche(&ll); Loesche(&rl);
  1047.       }
  1048.       else beide_abl(&ll,&rl,li);
  1049.       Ausgabe(li,PotMsg3[2]);
  1050.     }
  1051.     Baum_abbauen(u); Baum_abbauen(v);
  1052.     Baum_abbauen(a); Baum_abbauen(b);
  1053.     return d;
  1054.   }
  1055.   if(k->pri==PRI_ADDSUB) {
  1056.     struct Knoten *l,*r;
  1057.     BOOL einfach=k->links && !k->rechts && !k->links->links ||
  1058.       k->rechts && !k->links && !k->rechts->links;
  1059.     if(!einfach) Ausgabe(li,ASMsg[0]);
  1060.     if(k->flags.is.Konst && k->konst!=0.) Ausgabe(li,ASMsg[1]);
  1061.     l=diffAdd(k->links,li);
  1062.     r=diffAdd(k->rechts,li);
  1063.     if(!l) Negiere(d=r);
  1064.     else if(!r) d=l;
  1065.     else d=Verkette(l,OP_SUB,r);
  1066.     D=d=Sinnlos(d); K=k;
  1067.     if(!einfach)
  1068.       Ausgabe(li,"&k differenziert ergibt also &d.");
  1069.     else if(!k->links) Ausgabe(li,ASMsg[2]);
  1070.     return d;
  1071.   }
  1072.   d=diffMul(k->links,&ll);
  1073.   if(k->rechts) {
  1074.     b=diffMul(k->rechts,&rl); a=d;
  1075.     u=NeuerK(OP_MUL);
  1076.     if(!k->links) u->konst=k->konst;
  1077.     else u->links=BaumKopie(k->links);
  1078.     u=Sinnlos(u);
  1079.     v=NeuerK(OP_MUL);
  1080.     v->links=BaumKopie(k->rechts);
  1081.     v=Sinnlos(v);
  1082.     if((art=Art())<0) return Neue_Konst(0.);
  1083.     muster=dDiv[art];
  1084.     d=Regeln();
  1085.   }
  1086.   if(k->links && k->flags.is.Konst && k->konst!=1.)
  1087.     d=Verkette(d,OP_MUL,Neue_Konst(k->konst));
  1088.   d=D=Sinnlos(d);
  1089.   K=k;
  1090.   if(!k->links) {
  1091.     Ausgabe(li,MDMsg[0]);
  1092.     if(!X(v)) {
  1093.       Ausgabe(li,"Wir berechnen also einmal die Ableitung von &v.");
  1094.       anhaengen(li,&rl);
  1095.       Ausgabe(li,MDMsg[1]);
  1096.     }
  1097.     else {
  1098.         Ausgabe(li,"v' ist natürlich 1 und wir erhalten &d.");
  1099.       Loesche(&rl);
  1100.     }
  1101.   }
  1102.   else {
  1103.     BOOL ko=k->flags.is.Konst && k->konst!=1.;
  1104.     if(ko) Ausgabe(li,MDMsg[2]);
  1105.     if(k->rechts) {
  1106.       Ausgabe(li,MDMsg[3]);
  1107.       beide_abl(&ll,&rl,li);
  1108.       Ausgabe(li,MDMsg[4]);
  1109.       if(ko) Ausgabe(li,"Dabei wurde noch mit der Konstanten &# multipliziert.");
  1110.     }
  1111.     else {
  1112.       anhaengen(li,&ll);
  1113.       if(ko) Ausgabe(li,"Als Ergebnis von &k erhalten wir also &d.");
  1114.     }
  1115.   }
  1116.   if(k->rechts) {
  1117.     Baum_abbauen(u); Baum_abbauen(v);
  1118.     Baum_abbauen(a); Baum_abbauen(b);
  1119.   }
  1120.   return d;
  1121. }
  1122.  
  1123. void diff(char *formel,struct list *l)
  1124. {
  1125.   errno=0;
  1126.   if(Term_korrekt(formel) && (K=Root=Baum_aufbauen(formel)) && errno==0) {
  1127.     Ausgabe(l,"Angabe: &k");
  1128.     D=Differenziere(Root,l);
  1129.     Ausgabe(l,"Endergebnis: &d");
  1130.     Baum_abbauen(D);
  1131.     Baum_abbauen(Root);
  1132.   }
  1133.   else Ausgabe(l,"Angabe fehlerhaft!");
  1134. }
  1135.  
  1136. struct IntuitionBase *IntuitionBase;
  1137. struct GfxBase *GfxBase;
  1138. struct Window *w;
  1139. struct RastPort *rp;
  1140. UBYTE Formel[256],AlteFormel[256],Kopie[256];
  1141. struct StringInfo si_Eingabe={Formel,AlteFormel,0,256};
  1142. struct Gadget gg_Eingabe={
  1143. NULL,20,25,520,11,GADGHCOMP,RELVERIFY,
  1144. STRGADGET,NULL,NULL,NULL,0,(APTR)&si_Eingabe,1,NULL};
  1145. struct NewWindow nw={
  1146. 10,10,560,160,0,1,
  1147. GADGETUP|CLOSEWINDOW|RAWKEY,
  1148. WINDOWDRAG|WINDOWCLOSE|WINDOWDEPTH|ACTIVATE,&gg_Eingabe,
  1149. NULL,(UBYTE *)"How-To-Derive ...  1992 by Markus Öllinger  (c) by M&T",
  1150. NULL,NULL,0,0,0,0,WBENCHSCREEN};
  1151.  
  1152. void Male(long x,long y,int w,char *t)
  1153. {
  1154.   SetDrMd(rp,JAM1);
  1155.   x=x+(w>>1)-(strlen(t)<<2);
  1156.   SetAPen(rp,2);Move(rp,x+1,y+7);
  1157.   Text(rp,t,(long)strlen(t));
  1158.   SetAPen(rp,1);Move(rp,x,y+6);
  1159.   Text(rp,t,(long)strlen(t));
  1160. }
  1161.  
  1162. void ende(int err)
  1163. {
  1164.   if(w) CloseWindow(w);
  1165.   if(GfxBase) CloseLibrary((struct Library *)GfxBase);
  1166.   if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  1167. }
  1168.  
  1169. void init(void)
  1170. {
  1171.   atexit(ende);
  1172.   if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",33)))
  1173.     exit(1);
  1174.   if(!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",33)))
  1175.     exit(1);
  1176.   if(!(w=OpenWindow(&nw))) exit(2);
  1177.   rp=w->RPort;
  1178.   SetRast(rp,3); RefreshWindowFrame(w);
  1179.   SetAPen(rp,0); RectFill(rp,20,50,540,145);
  1180.   ActivateGadget(&gg_Eingabe,w,NULL);
  1181.   Male(0,15,560,"Angabe  f(x)=?");
  1182.   Male(0,40,560,"Lösungsweg");
  1183. }
  1184.  
  1185. void Zeige(struct node *n,long scroll,int s,int e)
  1186. {
  1187. int i;
  1188.   SetAPen(rp,1); SetBPen(rp,0);
  1189.   if(scroll) ScrollRaster(rp,0,scroll,20,50,540,145);
  1190.   for(i=0;n && i<e;n=n->next,i++) if(i>=s) {
  1191.     Move(rp,20,(long)(56+(i<<3)));
  1192.     Text(rp,n->s,(long)strlen(n->s));
  1193.   }
  1194. }
  1195.  
  1196. void main(int argc,char **argv)
  1197. {
  1198. struct IntuiMessage *msg;
  1199. ULONG class; USHORT code;
  1200. struct list l;
  1201. struct node *show=l.first=NULL;
  1202.   init();
  1203.   do {
  1204.     WaitPort(w->UserPort);
  1205.     msg=(struct IntuiMessage *)GetMsg(w->UserPort);
  1206.     class=msg->Class; code=msg->Code;
  1207.     ReplyMsg((struct Message *)msg);
  1208.     if(class==GADGETUP) {
  1209.       Loesche(&l); l.first=NULL;
  1210.       diff(strcpy(Kopie,Formel),&l);
  1211.       SetAPen(rp,0); RectFill(rp,20,50,540,145);
  1212.       Zeige(show=l.first,0,0,12);
  1213.     }
  1214.     else if(class==RAWKEY) {
  1215.       if(code==0x4c && show->prev) Zeige(show=show->prev,-8,0,1);
  1216.       else if(code==0x4d && show->next) Zeige(show=show->next,8,11,12);
  1217.       else if(code==0x45) break;
  1218.       else if(code==0x44) ActivateGadget(&gg_Eingabe,w,NULL);
  1219.     }
  1220.   } while(class!=CLOSEWINDOW);
  1221.   Loesche(&l);
  1222.   exit(0);
  1223. }
  1224.  
  1225.